package Tracer;

import java.util.LinkedList;

/**
 *@author Lorraine
 */

/**
 * ClassName : ThreadPool It is a class as a pool to maintain many tasks,threads
 * will grab a free task from this pool and execute it.
 * 
 * @version 1.0 Sep. 10th 2009
 * @author PENG ZHANG
 */
public class ThreadPool extends ThreadGroup {
	/**
	 * Whether the thread pool is closed or not
	 */
	private boolean isClosed = false; // if the thread pool closed
	/**
	 * a work queue to store tasks
	 */
	private LinkedList<Runnable> workQueue; // work queue

	/**
	 * Constructor of thread pool class
	 * 
	 * @param poolSize
	 *            the size of pool
	 */
	public ThreadPool(int poolSize) { // poolSize represent number of working
		// threads
		super(1 + ""); // 1 is the thread pool ID.
		setDaemon(true); // true, watch the thread pool
		workQueue = new LinkedList<Runnable>(); // create a work queue
		for (int i = 0; i < poolSize; i++) {
			new WorkThread(i).start(); // create and start working threads
		}
	}

	/**
	 * add a new task to work queue
	 * 
	 * @param a
	 *            runnable task
	 */
	public synchronized void execute(Runnable task) {
		if (isClosed) {
			throw new IllegalStateException();
		}
		if (task != null) {
			workQueue.add(task);// add a task
			notify(); // wake up a thread which is waiting in getTask()
		}
	}

	/**
	 * working thread get a task from work queue by this method
	 * 
	 * @param threadid
	 *            a id to identify the thread
	 */
	private synchronized Runnable getTask(int threadid)
			throws InterruptedException {
		while (workQueue.size() == 0) {
			if (isClosed)
				return null;
			wait(); // if no task exist in work queue, blocked and wait
		}
		// thread start to execute
		return (Runnable) workQueue.removeFirst(); // return first element and
		// remove it
	}

	/**
	 * close the thread pool
	 */
	public synchronized void closePool() {
		if (!isClosed) {
			waitFinish(); // wait until threads finish
			isClosed = true;
			workQueue.clear(); // clear the work queue
			interrupt(); // interrupt all working threads
		}
	}

	/**
	 * wait until all tasks finish
	 */
	public void waitFinish() {
		synchronized (this) {
			isClosed = true;
			notifyAll(); // wake up all tasks waiting in getTask()
		}
		Thread[] threads = new Thread[activeCount()]; // activeCount() return
		// estimated value of active threads
		int count = enumerate(threads); // enumerate()inherit from ThreadGroup
		// and return all active threads
		for (int i = 0; i < count; i++) { // wait until all tasks finish
			try {
				threads[i].join();
			} catch (InterruptedException ex) {
				ex.printStackTrace();
			}
		}
	}

	/**
	 * inner class, work thread
	 */
	private class WorkThread extends Thread {
		private int id;

		public WorkThread(int id) {
			// add threads to thread pool
			super(ThreadPool.this, id + "");
			this.id = id;
		}

		public void run() {
			while (!isInterrupted()) { // isInterrupted()to judge whether
				// interrupted
				Runnable task = null;
				try {
					task = getTask(id); // get out the tasks
				} catch (InterruptedException ex) {
					ex.printStackTrace();
				}
				// if return null from getTask()or being interrupted by
				// getTask(), finish the current thread
				if (task == null)
					return;
				try {
					task.run(); // run the task
				} catch (Throwable t) {
					t.printStackTrace();
				}
			}// end while
		}// end run
	}// end workThread
}
